import Compose, { Middleware, Next } from "../Compose";
import Context from "../Context";
import URLParse from "url-parse";

export enum MethodType {
  GET = "GET",
  PUT = "PUT",
  POST = "POST",
  DELETE = "DELETE"
}

export interface IRouterState {
  url: URLParse;
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface EmpatyState {
}

export type RouteMiddleWare<T = EmpatyState> = Middleware<Context<IRouterState & T>>;

export interface IRouteConfig {
  regx: RegExp; // 路径
  method: MethodType; // 类型
  middleware: RouteMiddleWare;
}

export class Router {
  private static _instance: Router;
  private readonly _routeConfig: IRouteConfig[];

  private constructor() {
    this._routeConfig = [];
    this._hostname = new URLParse(location.href).hostname;
  }

  private _hostname: string;

  set hostname(hostname: string) {
    this._hostname = hostname;
  }

  public static instance(): Router {
    if (!Router._instance) {
      Router._instance = new Router();
    }
    return Router._instance;
  }

  public addRoutes(configs: IRouteConfig[]) {
    this._routeConfig.push(...configs);
  }

  public addRoute(config: IRouteConfig) {
    this._routeConfig.push(config);
  }

  public routes(): Middleware<Context<IRouterState>> {
    const _routes = this._routeConfig;
    const _router = this;

    const dispatch = function dispatch(ctx: Context<IRouterState>, next: Next) {
      const _url: URLParse = new URLParse(ctx.req.url);
      ctx.state.url = _url;
      if (_url.hostname.indexOf(_router._hostname) == -1) {
        console.log("不可截获 进入下一个中间件");
        return next();
      }

      const _routeChain: Middleware<Context>[] = [];

      // 匹配路由和方法
      _routes.forEach(item => {
        if (item.method == ctx.req.method && item.regx.test(_url.pathname)) {
          console.log("路径和方法匹配了");
          _routeChain.push(item.middleware);
        }
      });

      if (_routeChain.length < 1) {
        console.log("没有匹配任何路由");
        return next();
      }

      return Compose<Context>(_routeChain)(ctx, next);
    };

    return dispatch;
  }
}
